#include "perspective_view.h"
#include "fixed_point_camera.h"
#include "first_person_camera.h"
#include "model/matrix4x4.h"
#include "draw_utils.h"
#include "model/cart_model.h"
#include <iostream>

PerspectiveView::PerspectiveView(Rectangle viewport,GLuint axisHandle,GLuint gridHandle,PerspectiveModel& pModel)
	: 	View(viewport),
		pModel(pModel){
	hAxis = axisHandle;
	hGrid = gridHandle;

	// Se agrega una camara por defecto
	this->activeCamera = this->addCamera(new FixedPointCamera());
	//this->activeCamera = this->addCamera(new FirstPersonCamera());
}

PerspectiveView::~PerspectiveView(){
	for(std::vector<Camera*>::iterator it=this->cameras.begin();it!=this->cameras.end();++it){
		delete *it;
	}
}

void PerspectiveView::setEnv(){
	glViewport ((GLint) viewport.x1,(GLint) viewport.y1, (GLsizei) viewport.width(), (GLsizei) viewport.height());
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluPerspective(60.0, (GLfloat) viewport.width()/(GLfloat) viewport.height(), 0.10, 100.0);
}

void PerspectiveView::display(){
	setEnv();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	getActiveCamera().applyCamera();


	glEnable(GL_LIGHTING);

	glCallList(hAxis);
	glCallList(hGrid);

	glPushMatrix();
		float material_color[3]={0.0f, 1.0f, 0.0f};
		glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,material_color);

		drawRail(pModel.getRCModel().getRailPoints());

		float material_color2[3]={0.4f, 0.4f, 0.4f};
		glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,material_color2);
	glPopMatrix();

	glDisable(GL_LIGHTING);
	drawCurveShadow();
	glEnable(GL_LIGHTING);

	CartModel& cModel = this->pModel.getCartModel();

	if(cModel.getLightState()){
		glEnable(cModel.getLightId());
	}else
		glDisable(cModel.getLightId());


	drawSurface(pModel.getRCModel().getSurfacePoints(),
				pModel.getRCModel().getNormalSurface(),
				pModel.getRCModel().getIndex(),
				pModel.getRCModel().getPointCountBySegment());

	drawCart();

	if(cModel.getLightState())
		glDisable(cModel.getLightId());

	drawColumns();

	glDisable(GL_LIGHTING);

}

void PerspectiveView::drawSurface(const Points& points,const Points& normalPoints,const std::vector<unsigned int>& index,const std::vector<unsigned int> sizeofSegments){
	if (!sizeofSegments.size())
		return;

	glEnable(GL_NORMALIZE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, 0, (float*)points._M_impl._M_start);
	glNormalPointer(GL_FLOAT, 0, (float*)normalPoints._M_impl._M_start);
	unsigned int* indexPointer=index._M_impl._M_start;
	for(unsigned int i=0;i<sizeofSegments.size();i++){
		unsigned int indexSize=pModel.getRCModel().getIndexSize(i);
		glDrawElements(GL_TRIANGLE_STRIP, indexSize, GL_UNSIGNED_INT, indexPointer);
		indexPointer+=indexSize;
	}
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisable(GL_NORMALIZE);
}

void PerspectiveView::drawColumns(){
	std::vector<Column>::iterator it = pModel.getRCModel().getColumns().begin();
	for(;it!=pModel.getRCModel().getColumns().end();++it){
		//(it->drawColumn());
		glPushMatrix();
			glTranslatef((*it).getPosition().x1,(*it).getPosition().x2,0);
			glRotatef((*it).getTheta(),0,0,1);
			glScalef((*it).getDepth(),(*it).getWidth(),(*it).getHigh());
			DrawUtils::drawHalfColumn();
			glScalef(1.0,-1.0,1.0);
			DrawUtils::drawHalfColumn();
		glPopMatrix();
	}
}

void PerspectiveView::drawCurveShadow(){
	std::vector<Point>::const_iterator it=pModel.getRCModel().pointBegin();

	glColor3f(0.0f,1.0f,0.0f);
	glBegin(GL_LINE_LOOP);
	for(;it!=pModel.getRCModel().pointEnd();++it){
		glColor3f(1,0,0);
		glVertex2f(it->x1,it->x2);
	}
	glEnd();
}

void PerspectiveView::drawRail(std::vector<Point>& v){
	if(v.size()){
		Point* pointer = v._M_impl._M_start;
		std::vector<Point>::const_iterator it=pModel.getRCModel().pointBegin();
		for(unsigned int c=0;c<v.size()-1;c++,pointer+=4,++it){
			DrawUtils::drawSolid(pointer,*it,*++it,4);
			if(c==pModel.getRCModel().pointSize()-3)
				break;
		}

		//El primero con el ultimo
		Point points[8]={ 	v._M_impl._M_finish[-4],v._M_impl._M_finish[-3],
							v._M_impl._M_finish[-2],v._M_impl._M_finish[-1],
							v._M_impl._M_start[0],v._M_impl._M_start[1],
							v._M_impl._M_start[2],v._M_impl._M_start[3] };

		DrawUtils::drawSolid(points,*it,*pModel.getRCModel().pointBegin(),4);
	}
}

void PerspectiveView::drawCart(){
	CartModel& cModel = this->pModel.getCartModel();

	glEnable(GL_NORMALIZE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, 0, (float*)cModel.getPoints());
	glNormalPointer(GL_FLOAT, 0, (float*)cModel.getPoints());

	glPushMatrix();
		Point dir = cModel.getDirVector();
		glLightfv(GL_LIGHT3, GL_SPOT_DIRECTION, (float*)&dir);

		Point pos = cModel.getPosition();
		glTranslatef(pos.x1,pos.x2,pos.x3+cModel.getHeight()/1.1);
		glRotatef(cModel.getRotationAngleYZ(),0,0,-1);
		glRotatef(cModel.getRotationAngleXY(),1,0,0);

		glLightfv(GL_LIGHT3, GL_POSITION, CartModel::lightPos);

		glScalef(cModel.getWidth(),cModel.getDepth(),cModel.getHeight());
		glDrawElements(GL_TRIANGLE_STRIP, cModel.getIndexCount(), GL_UNSIGNED_INT, cModel.getIndices());
	glPopMatrix();

	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisable(GL_NORMALIZE);
}

void PerspectiveView::update(Observer* observer){
}

unsigned int PerspectiveView::addCamera(Camera* camera){
	this->cameras.push_back(camera);
	return this->cameras.size()-1;
}

unsigned int PerspectiveView::getActiveCameraNum(){
	return this->activeCamera;
}

Camera& PerspectiveView::getCamera(unsigned int num){
	return *this->cameras[num];
}

void PerspectiveView::removeCamera(unsigned int num){
	std::vector<Camera*>::iterator it=this->cameras.begin();
	unsigned int c=0;
	for(;c<num&&it!=this->cameras.end();c++,++it);
	if(c==num)
		this->cameras.erase(it);
}

Camera& PerspectiveView::getActiveCamera(){
	return *this->cameras[this->activeCamera];
}

void PerspectiveView::setActiveCamera(unsigned int num){
	if(num<this->cameras.size())
		this->activeCamera=num;
}
